/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit.handlers;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.uml2.uml.InteractionFragment;

import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseContainedFragmentsCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseCoveredCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.CaptureCoveredFragmentsCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.SelectPartCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CoverCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CreateCombinedFragmentCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CreateGraphicalElementCommand;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Handles creation of Combined Fragments.
 * <p>
 * This handler is used from DiagramLayoutPolicy.
 * </p>
 * 
 * @author frankd@ifi.uio.no
 */
public class CombinedFragmentCreateHandler extends InteractionFragmentCreateHandler {

	public CombinedFragmentCreateHandler(final EditPolicy hostPolicy) {
		super(hostPolicy);
	}

	@SuppressWarnings("unchecked")
	public Command[] getCreateCommands(final CreateRequest request,
			final Point location) {
		
		boolean isInitialised = initialize(request);
		if (! isInitialised) {
			Debug.log(new Exception("Command initialization error."));
			return null;
		}
		
		// AnalyseOwnerCommand [SeDi]
		// Find out which UML element should own the new element.
		// DecideCFBoundsCommand [SeDi]
		// Ensure that the new CF is properly contained within its owner.
		// SetBoundsHintCommand [SeDi]
		// Registers a Bounds hint that can be used when the
		// SeDi GraphcialElement is created.
		// CreateCombinedFragmentCommand [UML]
		// Creates the UML element and adds it to the UML interaction
		// When the command is executed, a GraphicalElement will be
		// created in response to the notification. This creation will
		// consume the Bounds hint set previously
		// AnalyseCoveredCommand [SeDi]
		// Analyses the diagram and detects any lifelines covering the
		// new fragment. The result is input to the next command:
		// CoverCommand [UML]
		// Sets the fragment's Covered attribute.

//		// First, select which interaction this fragment should belong to
//		final GraphicalEditPart host = (GraphicalEditPart) hostPolicy.getHost();
//		final GraphNode interactionView = selectInteraction(request);
//		final Diagram diagram = LookForElement.getDiagram(interactionView);
//		final Rectangle bounds = new Rectangle(location,
//				request.getSize() != null ? request.getSize() : new Dimension(
//						0, 0));
//		if (host instanceof FrameEditPart)
//			host.getFigure().translateToParent(bounds);
//		host.getFigure().getParent().translateToAbsolute(bounds);

//		final AnalyseOwnerCommand ownerCmd = new AnalyseOwnerCommand();
//		ownerCmd.setLocation(absolutLoc);
//		ownerCmd.setDiagram(diagram);
//		ownerCmd.setAnyEditPart(interactionEP);

//		final DecideCFBoundsCommand decideBoundsCmd = new DecideCFBoundsCommand();
//		decideBoundsCmd.setDiagram(diagram);
//		decideBoundsCmd.setHint(bounds);
//		decideBoundsCmd.setAnyEditPart(interactionEP);

		final CreateCombinedFragmentCommand createCmd = 
			new CreateCombinedFragmentCommand(coveredLifelines, interaction);
		
		final CreateGraphicalElementCommand createGECmd = 
			new CreateGraphicalElementCommand();
		createGECmd.setAnyEditPart(interactionEP);
		createGECmd.setParentGE(interactionNode);

//		// ownerCmd.execute();
//		decideBoundsCmd.setOwner(ownerCmd.getOwner());
//		// decideBoundsCmd.execute();
//
//		final SetBoundsHintCommand hintCmd = new SetBoundsHintCommand();

		
		// glue: namespace

		final AnalyseCoveredCommand analyseCoveredCmd = new AnalyseCoveredCommand();
		analyseCoveredCmd.setEditPart(interactionEP);

		final CoverCommand coverCmd = new CoverCommand();

		final AnalyseContainedFragmentsCommand analyseCaptureCmd = new AnalyseContainedFragmentsCommand();
		analyseCaptureCmd.setAnyEditPart(interactionEP);
		// glue: CombinedFragmentView

		final CaptureCoveredFragmentsCommand captureCmd = new CaptureCoveredFragmentsCommand();
		// glue: Capture

		final SelectPartCommand selectCmd = new SelectPartCommand();
		selectCmd.setAnyEditPart(interactionEP.getRoot());
		selectCmd.setSelectForEdit(true);

//		final Command glue1 = new Command() {
//			public void execute() {
//				decideBoundsCmd.setOwner(ownerCmd.getOwner());
//				createCmd.setNamespace(ownerCmd.getOwner());
//			}
//		};
//
//		final Command glue2 = new Command() {
//			public void execute() {
//				Rectangle b = decideBoundsCmd.getPreferredBounds();
//				GraphicalEditPart diagramEditPart = (GraphicalEditPart) interactionEP
//						.getViewer().getEditPartRegistry().get(diagram);
//				diagramEditPart.getFigure().translateToRelative(b);
//				hintCmd.setHint(b);
//			}
//		};

		final Command glueGE = new Command() {
			@Override
			public void execute() {
				createGECmd.setElement(createCmd.getCombinedFragment());
			}
		};

		final Command glue3 = new Command() {
			@SuppressWarnings("unchecked")
			public void execute() {
				InteractionFragment fragment = createCmd.getCombinedFragment();
				List<GraphNode> listFrag = LookForElement
						.lookForGraphElementWODiagram(fragment, diagram,
								new ArrayList<GraphNode>(1));
				GraphNode fragmentView = listFrag.get(0);
				analyseCoveredCmd.setFragmentView(fragmentView);
			}
		};

		final Command glue4 = new Command() {
			public void execute() {
				coverCmd.setFragment(createCmd.getCombinedFragment());
				coverCmd.setCovered(analyseCoveredCmd.getCovered());
				selectCmd.setTarget(createCmd.getCombinedFragment());
			}
		};

		final Command glue5 = new Command() {
			public void execute() {
				List<GraphNode> listCFrag = LookForElement
						.lookForGraphElementWODiagram(createCmd
								.getCombinedFragment(), diagram,
								new ArrayList<GraphNode>(1));
				GraphNode cfView = listCFrag.get(0);
				analyseCaptureCmd.setCombinedFragmentView(cfView);
			}
		};

		final Command glue6 = new Command() {
			public void execute() {
				captureCmd.setCapture(analyseCaptureCmd.getContained());
			}
		};

//		return new Command[] { ownerCmd, glue1, decideBoundsCmd, glue2,
//				hintCmd, createCmd, glueGE, createGECmd, glue3,
//				analyseCoveredCmd, glue4, coverCmd, glue5, analyseCaptureCmd,
//				glue6, captureCmd, selectCmd };
		return new Command[] { 
//				ownerCmd, glue1, 
//				decideBoundsCmd, glue2,
//				hintCmd, 
				createCmd, glueGE, 
				createGECmd, glue3,
				analyseCoveredCmd, glue4, 
				coverCmd, glue5, 
				analyseCaptureCmd, glue6, 
				captureCmd, 
				selectCmd };
	}

//	/**
//	 * Select the Interaction that the new CombinedFragment will belong to. We
//	 * select the closest one, measured from top-left corners.
//	 */
//	private GraphNode selectInteraction(final CreateRequest request) {
//
//		if (interactionEP instanceof FrameEditPart)
//			return interactionNode;
//
//		final Rectangle requestedBounds = new Rectangle(request.getLocation(),
//				request.getSize() != null ? request.getSize() : new Dimension(
//						0, 0));
//
//		GraphNode best = null;
//		int bestDistance = Integer.MAX_VALUE;
//
//		for (Interaction interaction : ModelUtil.getInteractions(diagram)) {
//			List<GraphNode> listInter = 
//				LookForElement.lookForGraphElementWODiagram(
//						interaction, 
//						diagram,
//						new ArrayList<GraphElement>(1));
//			final GraphNode intView = listInter.get(0);
//
//			final int distance = new Rectangle(intView.getPosition(), intView
//					.getSize()).getCenter().getDistance2(
//					requestedBounds.getCenter());
//
//			if (distance <= bestDistance) {
//				bestDistance = distance;
//				best = intView;
//			}
//		}
//
//		return best;
//	}
}
